Since 2015, JavaScript has improved immensely.
It’s much more pleasant to use it now than ever.
In this article, we’ll look at maps and weak maps.
Iterating and Looping Through Maps
We can iterate and loop through maps with various methods.
Map.prototype.entries
returns an iterable object with arrays of key-value pair arrays for each entry of our map.
Map.prototype.forEach
takes a callback that has the signature (value, key, collection)
to let us loop through the map.
value
has the value of the map entry.
key
has the key of the map entry.
collection
has the map itself.
The 2nd argument of it is the value of this
inside the callback.
Map.prototype.keys
returns an iterable with the keys of the map.
Map.prototype.values
returns an iterable of all values in the map.
Map.prototype[Symbol.iterator]
is the default method for iterating through maps.
It returns an iterable with the key-value pair arrays.
WeakMap
WeakMaps work mostly like maps.
WeakMaps keys are objects. They’re weakly held.
We can’t get an overview of all the entries with a WeakMap.
And we can’t clear a WeakMap.
We’ve to put in objects as keys, so we can’t write;
const wm = new WeakMap()
wm.set('foo', 123);
since we’ll get a TypeError doing so.
But we can write:
const wm = new WeakMap()
wm.set({}, 123);
The WeakMap keys are weakly held.
This means that an object that isn’t referred to by anything like an object or a property can be garbage collected.
We can’t access them unless they’re held somewhere.
Once the key is gone, then the entry will disappear.
We can’t get an overview of a WeakMap.
This is because there’s no way to inspect the innards of it.
The only way to get the content of a WeakMap is to get the content by the key.
The use case of a WeakMap includes things like caching, managing listeners, and keeping private data.
With WeakMaps, we can cache an object with it, as we can only have object keys.
For example, we can write:
const cache = new WeakMap();
function countOwnKeys(obj) {
if (cache.has(obj)) {
return cache.get(obj);
} else {
const num = Math.random();
cache.set(obj, num);
return num;
}
}
to create a WeakMap and get the entry if the key exists
Otherwise, we add an entry to the WeakMap.
We can also use them to store the listeners in a WeakMap.
For instance, we can write:
const listeners = new WeakMap();
function addListener(obj, listener) {
if (!listeners.has(obj)) {
listeners.set(obj, new Set());
}
listeners.get(obj).add(listener);
}
We have the addListener
function to add an event listener to the set if it doesn’t already exist.
If obj
isn’t in the WeakMap, then we create an entry the obj
as the key and a set as the value.
It’s also useful for keeping private data as we need the reference to the key object to get the entry.
So we can write:
const _counter = new WeakMap();
class Countdown {
constructor(counter) {
_counter.set(this, counter);
}
increment() {
let counter = _counter.get(this);
if (counter < 1) {
return;
}
counter++;
_counter.set(this, counter);
}
}
to store the counter
in the WeakMap with the set
method call in the constructor.
In the increment
method, we get the counter with the _counter.get
method.
Then we increment the counter
and set the new value with set
.
Conclusion
We can iterate through maps with various methods.
Also, WeakMaps can be used to store private data, caching, and more.